#include "hash-table.h"
#include "spisok.h"
#include<stdlib.h>
#include<stdio.h>
#include<conio.h>
#include<string.h>

void ht_init(HashTable *ht, size_t size, HashFunction hf, Destructor dtor)
{
        //SList *list;
        int i;
        ht->size=size;
        ht->table=(SList**)malloc(size*sizeof(SList*));
                
                for(i=0;i<ht->size;i++)
                {
                                
                 ht->table[i]=NULL;
                        

                        
                }
        if(hf!=NULL)
        {
                ht->hashfunc=hf;
                
        }
        else
        {
                ht->hashfunc=jenkins_one_at_a_time_hash;
        }

        
                ht->dtor=dtor;
        
       
        
}
void _f(Pointer data, Pointer user_data)
{
	struct Note* t;
	HashTable* ht;
	ht=user_data;
	t=data;
	ht->dtor(t->value);
	free(t);
}

void ht_destroy(HashTable *ht)
{
        SList* t;
        SList* ptr;
		struct Note* n;
		int i=0;
			for(i=0;i<ht->size;i++)
			{
				t=ht->table[i];
				if(t!=NULL)
				{
					slist_foreach(t, _f,ht);
					free(t);
				}


			}
      
          
			free(ht->table);

}

int _set(Pointer data, Pointer user_data)
{
   struct Note * pCurrent = data;
  struct Note * pSet = user_data;

        if ( strcmp(pCurrent->key, pSet->key) == 0 )
        {
                pCurrent->value = pSet->value;
                return 0;
        }
        return 1;

}

void ht_set(HashTable *ht, char *key, Pointer data)
{
        unsigned index;
        SList*t;
                struct Note newNote;

                newNote.value = data;
                strcpy(newNote.key, key);
                newNote.h = ht->hashfunc(key);
        
        index = newNote.h % ht->size;
        t = ht->table[index];
                
                if ( slist_foreach(t, _set, &newNote) )
                {
                        struct Note * pNote = malloc(sizeof(struct Note));

                        pNote->value = data;
                        strcpy(pNote->key, key);
                        pNote->h = ht->hashfunc(key);

                ht->table[index] = slist_append(ht->table[index], pNote);
                }

}
Pointer _get(Pointer data, Pointer user_data)
{
	struct Note* n;
	n=data;
	if(strcmp(n->key,user_data) == 0)
	{
		printf(n->value);
	}
	return 1;
}
Pointer ht_get(HashTable *ht, char *key)
{
        size_t index;
        SList * t;
		struct Note* n;
		 index=ht->hashfunc(key) % ht->size;
        t = ht->table[index];
		slist_foreach(t, _get, key);
       
        
                
}

int _has(Pointer data, Pointer user_data)
{
	struct Note* n;
	n=data;
	if(strcmp(n->key, user_data)==0)
	{
		return 1;
	}
	return 0;
}

int ht_has(HashTable *ht, char *key)
{
        size_t index;
        SList * t;
		struct Note* n;

        index    = ht->hashfunc(key) % ht->size;
        t = ht->table[index];
		slist_foreach(t, _has, key);
}

void _del(Pointer data, Pointer user_data)
{
	struct Note* n;
	n=data;
	if(strcmp(n->key, user_data)==0)
	{
		delete_student(n->value);
		free(n);
		
	}


}
void ht_delete(HashTable *ht, char *key)
{
	int i;
	unsigned index;
	SList*t;
	SList* ptr;
	struct Note* n;
	index=ht->hashfunc(key)% ht->size;
	
	
		t=ht->table[index];
		slist_foreach(t, _del, key);
		
		
	
}

/*
void ht_traverse(HashTable *ht, void (*func)(char *key, Pointer data))
{
        size_t i;
        List * t;

        for(i = 0; i < ht->size; i++)
        {
                t = ht->table[i];
                slist_foreach(t, func);
        }
}
*/
unsigned jenkins_one_at_a_time_hash(char *key) 
{
    unsigned hash = 0;

    for (; *key; ++key) {
        hash += *key;
        hash += (hash << 10);
        hash ^= (hash >> 6);
    }
    hash += (hash << 3);
    hash ^= (hash >> 11);
    hash += (hash << 15);
    return hash;
}
